package com.cy.pj.sys.service.impl;

import com.cy.pj.common.ShiroUtils;
import com.cy.pj.common.annotation.RequiredLog;
import com.cy.pj.common.exception.ServiceException;
import com.cy.pj.common.pojo.PageObject;
import com.cy.pj.sys.dao.SysUserDao;
import com.cy.pj.sys.dao.SysUserRoleDao;
import com.cy.pj.sys.entity.SysUser;
import com.cy.pj.sys.entity.SysUserDeptVo;
import com.cy.pj.sys.service.SysUserService;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

@Service
@Slf4j
//@Transactional(readOnly = false, rollbackFor = RuntimeException.class)
@Transactional(readOnly = false, rollbackFor = Throwable.class, isolation = Isolation.READ_COMMITTED)
public class SysUserServiceImpl implements SysUserService {
    @Autowired
    private SysUserDao sysUserDao;

    @Autowired
    private SysUserRoleDao sysUserRoleDao;

    @Override
    @RequiredLog(operation = "分页查询用户信息")
    @Transactional(readOnly = true) // 只读事务，多线程可以共享读
    public PageObject<SysUserDeptVo> findPageObjects(String username, Integer pageCurrent) {
        // 方式一：sql分页limit子句
        //// 1、参数校验
        //if(pageCurrent == null || pageCurrent < 1)
        //    throw new IllegalArgumentException("当前页码值无效");
        //// 2、获取用户总人数
        //int rowCount = sysUserDao.getRowCount(username);
        //if(rowCount == 0)
        //    throw new ServiceException("没有找到对应的记录");
        //// 3、获取当前页数据
        //int pageSize = 10;
        //int startIndex = (pageCurrent - 1) * pageSize;
        //// 4、返回数据
        //List<SysUserDeptVo> records =  sysUserDao.findPageObjects(username, startIndex, pageSize);
        //return new PageObject<SysUserDeptVo>(rowCount, pageSize, pageCurrent, records);

        // 方式二：mybatis分页插件
        // 1、参数校验

        // 2、启动配置
        System.out.println("SysUserServiceImpl.findPageObjects.Thread = " + Thread.currentThread().getName());
        int pageSize = 13;
        Page<SysUserDeptVo> page = PageHelper.startPage(pageCurrent, pageSize);
        // 3、执行分页查询(底层会在查询)
        List<SysUserDeptVo> records = sysUserDao.findPageObjects2(username);
        return new PageObject<>((int)page.getTotal(), pageSize, pageCurrent, records);
    }

    @Override
    @RequiredLog(operation = "启用/停用用户信息")
    @RequiresPermissions("sys:user:update")// 授权切入点方法
    public int validById(Integer id, Integer valid, String modifiedUser) {
        // 1、验证数据
        if(id == null || id < 1)
            throw new IllegalArgumentException("id值不合法");
        // 2、更新用户的启用/停用状态
        int rows = sysUserDao.validById(id, valid, modifiedUser);
        if(rows == 0)
            throw new ServiceException("数据可能已经不存在");
        // 3、返回值
        return rows;
    }

    @Override
    @RequiredLog(operation = "保存用户信息")
    @Transactional
    public int saveObject(SysUser entity, Integer[] roleIds) {
        // 1、校验
        if(entity == null)
            throw new IllegalArgumentException("保存对象不能为空");
        if(entity.getUsername() == null || entity.getUsername() == "")
            throw new IllegalArgumentException("用户名不能为空");
        if(entity.getPassword() == null || entity.getPassword() == "")
            throw new IllegalArgumentException("密码不能为空");
        if(roleIds == null || roleIds.length == 0)
            throw new IllegalArgumentException("至少要为用户分配一个角色");
        // 2、保存用户自身信息
        String source = entity.getPassword();
        String salt = UUID.randomUUID().toString();
        SimpleHash sh = new SimpleHash("MD5", source, salt, 1);
        entity.setSalt(salt);
        entity.setPassword(sh.toHex());
        int rows = sysUserDao.insertObject(entity);
        sysUserRoleDao.insertObjects(entity.getId(), roleIds);
        //sysUserRoleDao.insertObjects(entity.getId(), null);// 产生异常,测试事务
        // 3、
        return rows;
    }

    @Override
    public Map<String, Object> findObjectById(Integer id) {
        SysUserDeptVo user = sysUserDao.findObjectById(id);
        List<Integer> roleIds = sysUserRoleDao.findRoleIdsByUserId(id);
        Map<String, Object> map = new HashMap<>();
        map.put("user", user);
        map.put("roleIds", roleIds);
        return map;
    }

    @RequiredLog(operation = "更新用户信息")
    @Override
    public int updateObject(SysUser entity, Integer[] roleIds) {
        int rows = sysUserDao.updateObject(entity);
        if(rows == 0)
            throw new ServiceException("用户可能已经不存在");
        sysUserRoleDao.deleteObjectsByUserId(entity.getId());
        sysUserRoleDao.insertObjects(entity.getId(), roleIds);
        return rows;
    }

    @Override
    public int updatePassword(String password, String newPassword, String cfgPassword) {
        // 1、参数校验：原密码
        //if(password == null || password == "")
        if(ObjectUtils.isEmpty(password))
            throw new IllegalArgumentException("原密码不能为空");
        // 2、参数校验：新密码和确认密码是否一致
        if(newPassword == null || newPassword.equals(""))
            throw new IllegalArgumentException("新密码不能为空");
        if(cfgPassword == null || cfgPassword.equals(""))
            throw new IllegalArgumentException("确认密码不能为空");
        if(!newPassword.equals(cfgPassword))
            throw new IllegalArgumentException("两次输入的密码不一致");
        // 3、获取当前用户信息
        //SysUser user = (SysUser)SecurityUtils.getSubject().getPrincipal();
        SysUser user = ShiroUtils.getUser();
        // 4、校验用户原密码
        SimpleHash hash = new SimpleHash(// 对原密码加密
                "MD5",
                password,
                user.getSalt(),
                1);
        if(!user.getPassword().equals(hash.toHex()))
            throw new ServiceException("原密码不正确");
        // 5、更新用户密码
        String salt = UUID.randomUUID().toString();// 生成新盐
        hash = new SimpleHash("MD5", newPassword, salt,1 );// 对新密码加密
        int rows = sysUserDao.updatePassword(hash.toHex(), salt, user.getId(), user.getUsername());
        if(rows == 0)
            throw new ServiceException("修改失败");
        // 6、返回影响行数
        return rows;
    }
}
